package gameClass;

import java.awt.Graphics;
import gameTypes.*;
import globals.Global;
import items.*;

/**
 * @author Ben Elliott
 */
public class PlayerCharacter extends DrawableObject {
	private final float MAX_SPEED = 1;
	
	/* Personal Attributes */
	public String name;
	private int life, mana;
	public boolean friendly;
	
	/* Status Attributes */
	private int experience, statPoints;
	
	/* Combat Attributes */
	private int attackRating, damage, defense;
	
	/* Containers */
	private Inventory inventory;
	private Equipment equipment;
	
	/* Technical Stuff */
	public int radius, range;
	public float xSpeed = 0, ySpeed = 0;
	private SpriteAnimation anim;
	private String direction = "none";
	public long timeout;
	
	// PlayerState
	
	public PlayerCharacter(String name) {
		this.drawableType = DrawableType.PlayerCharacter;
		this.name = name;
		this.radius = 32;
		this.range = 64;
		
		// Create animations
		anim = new SpriteAnimation(Global.Instance().playerSheet);
		anim.AddAnimation("downLeft",	0,  0,  32, 50, 4, 100.0f);
		anim.AddAnimation("down",		0, 50,  32, 50, 4, 100.0f);
		anim.AddAnimation("downRight",	0, 100, 32, 50, 4, 100.0f);
		anim.AddAnimation("left", 		0, 150, 32, 50, 4, 100.0f);
		anim.AddAnimation("upLeft", 	0, 200, 32, 50, 4, 100.0f);
		anim.AddAnimation("right",		0, 250, 32, 50, 4, 100.0f);
		anim.AddAnimation("upRight", 	0, 300, 32, 50, 4, 100.0f);
		anim.AddAnimation("up", 		0, 350, 32, 50, 4, 100.0f);
		setDirection("down");
		
		// Initialize fields
		location = new Vector2();
		inventory = new Inventory();
		equipment = new Equipment();
		
		// Test start location
		// 262144 is the max chunk due to floating point precision
		location = new Vector2(
				16777216/2,
				16777216/2);
	}
	
	public PlayerCharacter(String name, boolean friendly, int radius, int range) {
		this(name);
		this.friendly = friendly;
		this.range= range;
		this.radius = radius;
	}
	
	@Override
	public void Update(float elapsed) {
		this.anim.Update(elapsed);
		
		// Increment timeout for online characters
		timeout += elapsed;
		
		boolean diagonal = false;
		
		if (xSpeed>0.1 && ySpeed>0.1) {setDirection("downRight");diagonal=true;}
		if (xSpeed>0.1 && ySpeed<-0.1) {setDirection("upRight");diagonal=true;}
		if (xSpeed<-0.1 && ySpeed>0.1) {setDirection("downLeft");diagonal=true;}
		if (xSpeed<-0.1 && ySpeed<-0.1) {setDirection("upLeft");diagonal=true;}
		
		if (!diagonal) {
			if (xSpeed > 0.1) setDirection("right");
			else if (xSpeed < -0.1) setDirection("left");
			if (ySpeed > 0.1) setDirection("down");
			else if (ySpeed < -0.1) setDirection("up");
		}
		
		if (anim.GetAnimationByName(direction) != null) {
			if ( Math.abs(xSpeed) < 0.1 && Math.abs(ySpeed) < 0.1)
				anim.GetAnimationByName(direction).FrameCount = 1;
			else
				anim.GetAnimationByName(direction).FrameCount = 4;
		}
		
		/* Movement */
		if (xSpeed > MAX_SPEED) xSpeed = MAX_SPEED;
		if (ySpeed > MAX_SPEED) ySpeed = MAX_SPEED;
		if (xSpeed < -MAX_SPEED) xSpeed = -MAX_SPEED;
		if (ySpeed < -MAX_SPEED) ySpeed = -MAX_SPEED;
		move(xSpeed, ySpeed);
		xSpeed /= 1.2;
		ySpeed /= 1.2;
	}

	@Override
	public void Draw(Graphics graphics) {
		// Here we have hard coded tile sized based on the player sprite.
		this.anim.Draw(graphics,
				(int)(location.x - Global.Instance().camera.location.x) - 16,
				(int)(location.y - Global.Instance().camera.location.y) - 50);
		
		/*
		// Draw the player-to-tile collision space
		graphics.drawRect(
				(int)(location.x - Global.Instance().camera.location.x) - 16, 
				(int)(location.y - Global.Instance().camera.location.y) - Global.Instance().tileSize,
				32, 16);
		
		// Draw the characters radius
		graphics.drawOval(
				(int)(location.x - Global.Instance().camera.location.x) - radius, 
				(int)(location.y - Global.Instance().camera.location.y) - radius,
				radius*2, radius*2);
		
		// Draw the characters range
		graphics.drawOval(
				(int)(location.x - Global.Instance().camera.location.x) - range, 
				(int)(location.y - Global.Instance().camera.location.y) - range,
				range*2, range*2);
		*/
	}
	
	public void setDirection(String dir) {
		if (dir.compareTo(direction) != 0) {
			anim.setCurrentAnimation(dir);
			direction = dir;
		}
	}
	
	private void move(float x, float y) {
		// Check for tile collision

		
		// Find which chunk
		int firstxl = (int)((location.x + x + 1) / Global.Instance().tileSize);
		int chunkxl = firstxl / Global.Instance().chunkSize;
		int firstxr = (int)((location.x + x - 1) / Global.Instance().tileSize);
		int chunkxr = firstxr / Global.Instance().chunkSize;
		int firsty = (int)((location.y) / Global.Instance().tileSize);
		int chunky = firsty / Global.Instance().chunkSize;
		
		/*
		// LEFT RIGHT
		if (Global.Instance().tileMap.getTile(firstxl - 1, firsty).getIndex() == 0 &&
			Global.Instance().tileMap.getTile(firstxl - 1, firsty-1).getIndex() == 0 &&
			Global.Instance().tileMap.getTile(firstxr + 1, firsty).getIndex() == 0 &&
			Global.Instance().tileMap.getTile(firstxr + 1, firsty-1).getIndex() == 0) {
			location.x += x;
		} else {
			xSpeed = 0;
		}
		*/
		
		// LEFT RIGHT
		if (getChunkCollision((int)(location.x + x + 1), (int)location.y, -1, 0) &&
			getChunkCollision((int)(location.x + x + 1), (int)location.y, -1, -1) &&
			getChunkCollision((int)(location.x + x - 1), (int)location.y, +1, 0) &&
			getChunkCollision((int)(location.x + x - 1), (int)location.y, +1, -1)) {
			location.x += x;
		} else {
			xSpeed = 0;
		}
		
		// UP DOWN
		if (getChunkCollision((int)(location.x + 1), (int) (location.y + y), -1, 0) &&
			getChunkCollision((int)(location.x + 1), (int)(location.y + y), -1, -1) &&
			getChunkCollision((int)(location.x), (int)(location.y + y), 0, 0) &&
			getChunkCollision((int)(location.x), (int)(location.y + y), 0, -1) &&
			getChunkCollision((int)(location.x - 1), (int)(location.y + y), 1, 0) &&
			getChunkCollision((int)(location.x - 1), (int)(location.y + y), 1, -1)) {
			location.y += y;
		} else {
			ySpeed = 0;
		}

	}
	
	private boolean getChunkCollision(int x, int y, int tileShiftx, int tileShifty) {
		int tilex = x / Global.Instance().tileSize + tileShiftx;
		int tiley = y / Global.Instance().tileSize + tileShifty;
		
		int chunkx = tilex / Global.Instance().chunkSize;
		int chunky = tiley / Global.Instance().chunkSize;
		
		tilex %= Global.Instance().chunkSize;
		tiley %= Global.Instance().chunkSize;
		
		int tileType;
		try {
			tileType = Global.Instance().chunks.get(new Vector2(chunkx, chunky)).tileMap.getTile(tilex, tiley).index;
		} catch (Exception e) {
			return false;
		}
		
		if (tileType == 0)
			return true;
		
		return false;
	}

	public void equip(Armor item) {}
	public void addInventoryItem(Item item) {}

	
}
